﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using Mogre;
using MogreNewt;

namespace WastedMechanics
{
    public class Character : SelectableObject, IContainer
    {
        public enum ArmedCases
        {
            Nothing,
            Unarmed,
            Pistol,
            M1H
        }

        public enum ArmsAppearances
        {
            Full,
            Half,
            Hands,
            None
        }
     
        public Entity BodyEntity;
        public Entity ArmsEntity;
        public Entity HeadEntity;

        public SceneNode Node;
        public Body Body;
        public Vector3 Inertia;                

        public CharacterProfile Profile;
        
        public CharState.CharState State;                      
        
        public Vector3 Velocity;        

        public Body GroundSensor;
        public Node GroundSensorNode;
        public bool IsOnGround;
        public int SensedGround;
        
        public Node ClimbSensorNode;
        public Vector3 ClimbOrigin;

        Quaternion _orientation;
        public Degree HorizontalAngle;
        public Degree VerticalAngle;

        public SelectableObject Contact;                
        public IContainer PlunderedObject;
        
        public Vector3 AimPoint;
        public Degree LookAngle;         
                              
        public CharacterAnimBlender AnimBlender;

        private Equipment _equipment;
        
        public Entity PistolEntity;
        private ItemPistol _pistol;
        public Entity M1HEntity;
        private ItemM1H _m1hWeapon;
        private ItemArmour _Armour;        

        public Stack<CharTask> TaskStack;
        public CharTask CurrentTask;
        
        public event Action<Character, Item> OnPickedItem;
        public event Action<Character> OnStateChange;        
        public event Action<Character, SelectableObject> OnBeginBarter;
        public event Action<Character, SelectableObject> OnEndBarter;
        public event Action<Character> OnBeginEquip;
        public event Action<Character> OnEndEquip;
        public event Action<Character, IContainer> OnBeginPlunder;
        public event Action<Character, IContainer> OnEndPlunder;
        public event Action<Character, Character> OnSeeCharacter;
        public event Action<Character, Character> OnAttacked;
        public event Action<Character> OnDied;

        public float RunAcceleration;

        public bool CanTurn;
        public bool IsMoving;
        public bool IsJumping;
        public bool IsEquipping;
        public bool IsBartering;
        public bool IsPlundering;
        public bool IsTalking;
        public bool IsAiming;        
        
        public bool IsDead;
        public ArmedCases ArmedCase;

        public float RecoilTime;

        public List<Character> SeenCharacters;

        public bool InterpolateTurning = true;
        public Vector3 DesiredLookDirection;

        public SoundInstance SoundFootStep;       
        
        public Character(CharacterProfile profile)
        {
            Profile = profile.Clone();
            ShowName = true;
            IsObstacle = true;

            _orientation = Quaternion.IDENTITY;
            HorizontalAngle = 0;
            VerticalAngle = 0;

            SeenCharacters = new List<Character>();
                                 
            Node = Engine.SceneManager.RootSceneNode.CreateChildSceneNode();
            Armour = null;
            AnimBlender = new CharacterAnimBlender(this);
                                    
            CreateBody(Profile.BoundingBoxSize * 0.5f);
            CreateGroundSensor(Profile.BoundingBoxSize * 0.5f);
            CreateClimbSensor(Profile.BoundingBoxSize * 0.5f);
            
            _equipment = new Equipment();            

            TaskStack = new Stack<CharTask>();
            SwitchState(new CharState.CharStateIdleNothing(this));
        }

        public void SetAppearance(string bodyMeshName, ArmsAppearances armsVersion, bool headVisible)
        {
            if (AnimBlender != null)
                AnimBlender.SaveStatesParams();

            if (ArmsEntity != null)
            {
                Node.DetachObject(ArmsEntity);
                Engine.SceneManager.DestroyEntity(ArmsEntity);
                ArmsEntity = null;
            }

            if (HeadEntity != null)
            {
                Node.DetachObject(HeadEntity);
                Engine.SceneManager.DestroyEntity(HeadEntity);
                HeadEntity = null;
            }

            if (BodyEntity != null)
            {
                Node.DetachObject(BodyEntity);
                if (BodyEntity.SharesSkeletonInstance())
                    BodyEntity.StopSharingSkeletonInstance();
                Engine.SceneManager.DestroyEntity(BodyEntity);
                BodyEntity = null;
            }

            MeshPtr meshPtr = MeshManager.Singleton.Load(bodyMeshName, "General");
            ushort src, dest;
            if (!meshPtr.SuggestTangentVectorBuildParams(VertexElementSemantic.VES_TANGENT, out src, out dest))
            {
                meshPtr.BuildTangentVectors(VertexElementSemantic.VES_TANGENT, src, dest, true, true, true);
            }
 
            BodyEntity = Engine.SceneManager.CreateEntity(bodyMeshName);            
            Node.AttachObject(BodyEntity);
            
            if (armsVersion != ArmsAppearances.None)
            {
                if (Profile.ArmsMeshNames.ContainsKey(armsVersion))
                {
                    ArmsEntity = Engine.SceneManager.CreateEntity(Profile.ArmsMeshNames[armsVersion]);
                    BodyEntity.ShareSkeletonInstanceWith(ArmsEntity);
                    Node.AttachObject(ArmsEntity);
                }
            }            
                        
            if (headVisible && Profile.HeadMeshName != "")
            {
                HeadEntity = Engine.SceneManager.CreateEntity(Profile.HeadMeshName);
                BodyEntity.ShareSkeletonInstanceWith(HeadEntity);
                Node.AttachObject(HeadEntity);
            }

            if (AnimBlender != null)
                AnimBlender.ReloadParams();
        } 

        private void CreateBody(Vector3 scaledSize)
        {
            ConvexCollision collision = new MogreNewt.CollisionPrimitives.Capsule(
                Engine.NewtonWorld,
                System.Math.Min(scaledSize.x, scaledSize.z),
                scaledSize.y * 2,
                Vector3.UNIT_X.GetRotationTo(Vector3.UNIT_Y),
                Engine.GetUniqueBodyId());

            Vector3 offset;
            collision.CalculateInertialMatrix(out Inertia, out offset);

            Inertia *= Profile.BodyMass;
            
            Body = new Body(Engine.NewtonWorld, collision, true);
            Body.AttachNode(Node);
            Body.SetMassMatrix(Profile.BodyMass, Inertia);
            Body.AutoSleep = false;
            Body.ContinuousCollisionMode = 1;
            Body.IsGravityEnabled = false;

            Body.Transformed += BodyTransformCallback;
            Body.ForceCallback += BodyForceCallback;

            Body.UserData = this;
            Body.MaterialGroupID = Engine.MaterialManager.Materials["Character"];            

            Joint upVector = new MogreNewt.BasicJoints.UpVector(Engine.NewtonWorld, Body, Vector3.UNIT_Y);            

            collision.Dispose();
        }

        private void CreateGroundSensor(Vector3 scaledSize)
        {
            GroundSensorNode = Node.CreateChildSceneNode(new Vector3(0, -scaledSize.y, 0));
         
            ConvexCollision collision = new MogreNewt.CollisionPrimitives.Ellipsoid(
                Engine.NewtonWorld,
                new Vector3(1, 1, 1) * System.Math.Min(scaledSize.x, scaledSize.z) * 0.9f,
                Vector3.UNIT_X.GetRotationTo(Vector3.UNIT_Y),
                Engine.GetUniqueBodyId());

            GroundSensor = new Body(Engine.NewtonWorld, collision, true);
            GroundSensor.SetMassMatrix(1, new Vector3(1, 1, 1));
            GroundSensor.AutoSleep = false;               

            GroundSensor.UserData = this;
            GroundSensor.MaterialGroupID = Engine.MaterialManager.Materials["GroundSensor"];
        }

        private void CreateClimbSensor(Vector3 scaledSize)
        {
            ClimbSensorNode = Node.CreateChildSceneNode(new Vector3(0, scaledSize.y*0.5f, System.Math.Min(scaledSize.x, scaledSize.z)));
        }
        
        void BodyTransformCallback(Body sender, Quaternion orientation, Vector3 position, int threadIndex)
        {
            if (!IsDead)            
                Node.Position = position;            
            else            
                Node.Position = position - Orientation * -Vector3.UNIT_Z;  
            Node.Orientation = Orientation;
        }

        public void BodyForceCallback(Body body, float timeStep, int threadIndex)
        {            
            Body.AddForce(new Vector3(0, -40f * Body.Mass, 0));
            if (IsOnGround && !IsJumping && !IsDead)                            
                Body.Velocity = new Vector3(Velocity.x, System.Math.Min(0,Body.Velocity.y),Velocity.z);
            Body.Omega = Vector3.ZERO;
        }

        public void PushTask(CharTask task)
        {
            TaskStack.Push(task);
            CurrentTask = GetTopTask();            
        }

        public CharTask PopOutTask()
        {
            if (TaskStack.Count != 0)            
                return TaskStack.Pop();                                             
            return null;
        }
        public CharTask GetTopTask()
        {
            if (TaskStack.Count != 0)
            {
                CharTask task = TaskStack.Peek();
                task.Begin();
                return task;
            }
            return null;
        }

        public void SwitchState(CharState.CharState state)
        {
            if (State != null)
                State.Exit();
            State = state;            
            State.Enter();
            if (OnStateChange != null)
                OnStateChange(this);
        }

        public void UpdateSeenChars()
        {
            float sightRange = 15;
            foreach (var character in Engine.ObjectManager.CharactersList)
            {
                if (character != this && (character.Position - Position).Length < sightRange && !character.IsDead)
                {                    
                    
                    if (Mogre.Math.UnitRandom() < 1.0f/30)
                    if (!SeenCharacters.Contains(character))
                    {
                        Vector3 pointOnChar = new Vector3(
                            Mogre.Math.RangeRandom(-1, 1) * System.Math.Min(Body.Collision.AABB.HalfSize.x, Body.Collision.AABB.HalfSize.z),
                            Mogre.Math.RangeRandom(-1, 1) * Body.Collision.AABB.HalfSize.y,
                            Mogre.Math.RangeRandom(-1, 1) * System.Math.Min(Body.Collision.AABB.HalfSize.x, Body.Collision.AABB.HalfSize.z)
                            );
                        Raycaster.OnlyStatic raycast = new Raycaster.OnlyStatic();
                        raycast.Go(Engine.NewtonWorld, Position + Profile.HeadOffset, character.Position + pointOnChar);
                        if (raycast.ClosestHit.HitDistance < 0)
                        {
                            if (raycast.ClosestHit.HitDistance < 0)
                            {
                                Console.WriteLine("{0} see {1}", DisplayName, character.DisplayName);
                                SeenCharacters.Add(character);
                                if (OnSeeCharacter != null) OnSeeCharacter(this, character);
                            }
                        }                        
                    }                                   
                }
            }
            SeenCharacters.RemoveAll(character => (character.Position - Position).Length >= sightRange);
        }

        public override void Update()
        {
            AnimBlender.Update();   
            AnimBlender.TimeScale = 1.0f;
            RecoilTime -= Engine.FixedTimeStep;

            if (IsDead == false)
            {                
                VerticalAngle = Helper.Clamp(-80, 80, VerticalAngle);
                Orientation = Vector3.UNIT_Z.GetRotationTo((LookDirection * new Vector3(1, 0, 1)).NormalisedCopy);
                Node.Orientation = Orientation;

                GroundSensor.SetPositionOrientation(GroundSensorNode._getDerivedPosition(), Node.Orientation);

                UpdateSkeletonAiming();
                UpdateSeenChars();

                if (!IsTalking)
                {
                    if (CurrentTask == null)
                        CurrentTask = GetTopTask();
                    else
                    {
                        CurrentTask.Update();

                        if (CurrentTask.IsFinished)
                        {
                            CurrentTask.Done();
                            PopOutTask();
                            CurrentTask = GetTopTask();
                        }
                    }
                }
                

                if (InterpolateTurning)
                {
                    if (DesiredLookDirection != Vector3.ZERO)
                    {
                        Vector3 currLookDir = LookDirection;
                        LookDirection = (currLookDir + (DesiredLookDirection - currLookDir) * 0.2f).NormalisedCopy;
                    }
                }

                Contact = null;
                IsOnGround = (SensedGround > 0);
                if (SensedGround > 0)
                    SensedGround--; 
            }


            State.Update();                                              
        }

        private void UpdateSkeletonAiming()
        {
            Degree desiredAngle = 0;
            if (IsAiming)
                desiredAngle = -VerticalAngle;
            LookAngle += (desiredAngle - LookAngle) * 0.3f;

            if (Mogre.Math.Abs(LookAngle.ValueDegrees) < 0.01f)
            {
                if (BodyEntity.Skeleton.GetBone("Spine1").IsManuallyControlled
                    || BodyEntity.Skeleton.GetBone("Spine2").IsManuallyControlled)
                {
                    BodyEntity.Skeleton.GetBone("Spine1").SetManuallyControlled(false);
                    BodyEntity.Skeleton.GetBone("Spine2").SetManuallyControlled(false);
                }
            }
            else
            {
                if (!BodyEntity.Skeleton.GetBone("Spine1").IsManuallyControlled
                    || !BodyEntity.Skeleton.GetBone("Spine2").IsManuallyControlled)
                {
                    BodyEntity.Skeleton.GetBone("Spine1").SetManuallyControlled(true);
                    BodyEntity.Skeleton.GetBone("Spine2").SetManuallyControlled(true);
                }

                BodyEntity.Skeleton.GetBone("Spine1").Orientation = Helper.QuaternionFromAngle(180, Vector3.UNIT_Y)
                    * Helper.QuaternionFromAngle(90, Vector3.UNIT_X)
                    * Helper.QuaternionFromAngle(LookAngle * 0.45f, Vector3.UNIT_X);
                BodyEntity.Skeleton.GetBone("Spine2").Orientation = Helper.QuaternionFromAngle(LookAngle * 0.45f, Vector3.UNIT_X);
            }
        }

        public bool AddItem(Item item)
        {
            if (Equipment.AddItem(item))
            {
                if (OnPickedItem != null)
                    OnPickedItem(this, item);                
                return true;
            }
            return false;
        }

        public bool PickObject(Described target)
        {
            if (AddItem(target.Item))
            {
                Engine.ObjectManager.Destroy(target);
                return true;
            }
            return false;
        }

        public void TurnTo(Vector3 point)
        {
            DesiredLookDirection = (point - (Position + Profile.AimOffset)).NormalisedCopy;
            if (!InterpolateTurning)
                LookDirection = DesiredLookDirection;
        }

        public void StartClimb()
        {
            Raycaster.ClimbEdgeRaycast raycast = new Raycaster.ClimbEdgeRaycast();
            Vector3 climbRayStart = ClimbSensorNode._getDerivedPosition();
            Vector3 climbRayEnd = climbRayStart + new Vector3(0, 5, 0);
            raycast.Go(Engine.NewtonWorld, climbRayStart, climbRayEnd);
            if (raycast.ClimbEdge != null)
            {
                Vector3 climbEdgePosition = raycast.ClimbEdge.Body.Position;
                float climbDistA = ((raycast.ClimbEdge.A - climbRayStart) * new Vector3(1, 0, 1)).Length;
                float climbDistB = ((raycast.ClimbEdge.B - climbRayStart) * new Vector3(1, 0, 1)).Length;
                float angle = Mogre.Math.Abs(raycast.ClimbEdge.Direction.DotProduct(Orientation * Vector3.UNIT_Z));                
                if (climbDistA > 0.5f && climbDistB > 0.5f && angle >= 0.7f)
                {
                    ClimbOrigin = Position;
                    ClimbOrigin.y = climbEdgePosition.y - 0.7f;
                    State.ClimbOrder();
                }
            } 
        }

        public void TakePistol()
        {
            if (ArmedCase== ArmedCases.Nothing &&  Pistol != null)
            {
                State.TakePistol();          
            }
        }

        public void TakeM1H()
        {
            if (ArmedCase == ArmedCases.Nothing &&  M1HWeapon != null)
                State.TakeM1H();
        }

        public void Shoot()
        {
            Degree vanglediff = (-VerticalAngle - LookAngle);
            float hanglediff = Mogre.Math.Abs(
                ((AimPoint - Position) * new Vector3(1, 0, 1)).NormalisedCopy.DotProduct(Orientation * Vector3.UNIT_Z)
                );
            if (IsAiming && RecoilTime <= 0 && vanglediff < 2 && hanglediff >= 0.9f)
            {
                Vector3 pistolOrigin = Node.Position + Orientation * new Vector3(-0.15f, 0.65f, 0.1f);
                Vector3 direction = (AimPoint - pistolOrigin).NormalisedCopy;
                ProjectileBullet pb = new ProjectileBullet(this,
                    pistolOrigin,
                    (direction + 0.0f*new Vector3(Mogre.Math.UnitRandom() -0.5f, Mogre.Math.UnitRandom() -0.5f,Mogre.Math.UnitRandom() -0.5f)).NormalisedCopy,
                    Pistol.ProjectileSpeed,
                    Pistol.Damage,
                    Pistol.ProjectileMaterial);
                Engine.ObjectManager.Add(pb);     
                State.RecoilOrder();
                RecoilTime = Pistol.RecoilTime;

                SoundInstance soundShoot = Pistol.ShootSound.PlayNewInstance();
                soundShoot.SetPosition(Position);
 
            }
        }

        public void M1HHit(SelectableObject target=null)
        {
            State.M1HHitOrder(target);
        }


        public void ReceiveDamage(float dmg, SelectableObject cause=null)
        {
            if (!IsDead)
            {
                Profile.Stats.CurrentHP -= dmg;
                if (Profile.Stats.CurrentHP <= 0)
                    Die();
                else
                {
                    if (cause != null && cause is Character && OnAttacked != null)
                        OnAttacked(this, cause as Character);

                    SoundInstance argh = Engine.SoundManager.SoundEffects["argh" + (Helper.RandomInt(6) + 1).ToString() + ".wav"].PlayNewInstance();
                    argh.Volume = 0.2f;
                    argh.SetPosition(Position);
                }
            }
        }

        public void Die()
        {
            if (IsDead == false && State.GetType().Name != "CharStateDie")
            {
                SwitchState(new CharState.CharStateDie(this));
            }
        }

        public void MakeDead()
        {
            IsDead = true;
            if (OnDied != null) OnDied(this);
            Body.MaterialGroupID = Engine.MaterialManager.Materials["Transparent"];
            Body.SetPositionOrientation(Position + Orientation * -Vector3.UNIT_Z, Orientation);
            //Body.AutoSleep = true;            
            Node.Position = Position - Orientation * -Vector3.UNIT_Z;
            Profile.DisplayNameOffset.y *= 0.5f;
        }

        public void SetAnimation(string name)
        {
            AnimBlender.Target = AnimBlender.Anims[name];
        }

        public void ResetAnimation(string name)
        {
            AnimBlender.Anims[name].TimePosition = 0.0f;
        }
        
        public bool IsNotBusy()
        {
            return State.IsNotBusy() && !IsTalking && !IsBartering && !IsPlundering;
        }

        public override void BeginConversation(SelectableObject interlocutor)
        {
            IsTalking = true;           
            TurnTo(interlocutor.Position + (interlocutor is Character ? (interlocutor as Character).Profile.HeadOffset : Vector3.ZERO));
            base.BeginConversation(interlocutor);
        }

        public override void EndConversation()
        {
            IsTalking = false;
            base.EndConversation();
        }
        

        public void BeginBarter(SelectableObject interlocutor)
        {
            Interlocutor = interlocutor;
            if (OnBeginBarter != null) OnBeginBarter(this, Interlocutor);
            IsBartering = true;
        }

        public void EndBarter()
        {
            if (Interlocutor != null)
                if (OnEndBarter != null) OnEndBarter(this, Interlocutor);
            IsBartering = false;
            if (!IsTalking)
                Interlocutor = null;
        }

        public void BeginEquip()
        {
            if (OnBeginEquip != null) OnBeginEquip(this);
            IsEquipping = true;
        }

        public void EndEquip()
        {
            if (OnEndEquip != null) OnEndEquip(this);
            IsEquipping = false;
        }

        public void BeginPlunder(IContainer plundered)
        {
            PlunderedObject = plundered;
            if (OnBeginPlunder != null) OnBeginPlunder(this, PlunderedObject);
            IsPlundering = true;
        }

        public void EndPlunder()
        {
            if (OnEndPlunder != null) OnEndPlunder(this, PlunderedObject);
            IsPlundering = false;
            PlunderedObject = null;
        }

        public Vector3 LookDirection
        {
            get
            {
                Quaternion hrot = Helper.QuaternionFromAngle(HorizontalAngle, Vector3.UNIT_Y); 
                Quaternion vrot = Helper.QuaternionFromAngle(VerticalAngle, Vector3.UNIT_X);
                return hrot * vrot * Vector3.UNIT_Z;
            }
            set
            {
                VerticalAngle = Mogre.Math.ACos((value * new Vector3(1, 0, 1)).NormalisedCopy.DotProduct(value)) * Mogre.Math.Sign(-value.y);
                HorizontalAngle = Mogre.Math.ACos(Vector3.UNIT_Z.DotProduct((value * new Vector3(1,0,1)).NormalisedCopy)) * Mogre.Math.Sign(value.x);        
            }
        }

        public ItemPistol Pistol
        {
            get
            {
                return _pistol;
            }
            set
            {
                if (_pistol != null)
                {
                    BodyEntity.DetachObjectFromBone(PistolEntity);                    
                    Engine.SceneManager.DestroyEntity(PistolEntity);
                    _pistol.IsWorn = false;
                }                
                if (value != null)
                {
                    PistolEntity = Engine.SceneManager.CreateEntity(value.Profile.MeshName);
                    AttachPistolToPocket(value);
                }
                _pistol = value;
            }
        }

        public void AttachM1HWeaponToPocket(ItemM1H weapon)
        {
            if (M1HEntity.IsAttached)
                BodyEntity.DetachObjectFromBone(M1HEntity);
            Quaternion rotation = Helper.QuaternionFromAngle(90, Vector3.UNIT_X) * Helper.QuaternionFromAngle(-90, Vector3.UNIT_Z);
            BodyEntity.AttachObjectToBone("M1HPocket", M1HEntity, rotation, rotation * weapon.HandleOffset);
            weapon.IsWorn = true;
        }

        public void AttachM1HWeaponToHand(ItemM1H weapon)
        {
            if (M1HEntity.IsAttached)
                BodyEntity.DetachObjectFromBone(M1HEntity);
            Quaternion rotation = Helper.QuaternionFromAngle(90, Vector3.UNIT_X) * Helper.QuaternionFromAngle(-45, Vector3.UNIT_Z);
            BodyEntity.AttachObjectToBone("M1HHand", M1HEntity, rotation, rotation * weapon.HandleOffset);
        }

        public void AttachPistolToPocket(ItemPistol weapon)
        {            
            if (PistolEntity.IsAttached)
                BodyEntity.DetachObjectFromBone(PistolEntity);
            Quaternion rotation = Quaternion.IDENTITY;
            BodyEntity.AttachObjectToBone("PistolPocket", PistolEntity, rotation, rotation * weapon.HandleOffset);
            weapon.IsWorn = true;
        }

        public void AttachPistolToHand(ItemPistol weapon)
        {
            if (PistolEntity.IsAttached)
                BodyEntity.DetachObjectFromBone(PistolEntity);
            Quaternion rotation = Quaternion.IDENTITY;
            BodyEntity.AttachObjectToBone("PistolHand", PistolEntity, rotation, rotation * weapon.HandleOffset);
        }

        public ItemM1H M1HWeapon
        {
            get
            {
                return _m1hWeapon;
            }
            set
            {
                if (_m1hWeapon != null)
                {
                    BodyEntity.DetachObjectFromBone(M1HEntity);
                    Engine.SceneManager.DestroyEntity(M1HEntity); 
                    _m1hWeapon.IsWorn = false;
                }
                if (value != null)
                {
                    M1HEntity = Engine.SceneManager.CreateEntity(value.Profile.MeshName);
                    AttachM1HWeaponToPocket(value);
                }
                
                _m1hWeapon = value;
            }
        }

        public ItemArmour Armour
        {
            get
            {
                return _Armour;
            }
            set
            {
                if (_Armour != null)
                    _Armour.IsWorn = false;                       
                if (value != null)
                {
                    SetAppearance(value.BodyMeshName, 
                        value.ArmsAppearance, 
                        value.HeadVisibility);
                }
                else
                {
                    SetAppearance(Profile.DefaultBodyMeshName,
                        Profile.DefaultArmsAppearance,
                        Profile.DefaultHeadVisibility);
                }
                _Armour = value;
                if (_Armour != null)
                    _Armour.IsWorn = true;                   
            }
        }
                 
        public override Vector3 Position
        {
            get
            {
                return Body.Position;
            }
            set
            {
                if (IsDead == false)
                    Body.SetPositionOrientation(value, Orientation);
            }
        }

        public override Quaternion Orientation
        {
            get
            {
                return _orientation;
            }
            set
            {
                _orientation = value;
            }
        }

        public override string DisplayName
        {
            get
            {
                return Profile.DisplayName;
            }
            set
            {
                Profile.DisplayName = value;
            }
        }

        public override string Description
        {
            get
            {
                return Profile.Description;
            }
            set
            {
                Profile.Description = value;
            }
        }

        public override Vector3 DisplayNameOffset
        {
            get
            {
                return Profile.DisplayNameOffset;
            }
            set
            {
                Profile.DisplayNameOffset = value;
            }
        }

        public Equipment Equipment
        {
            get
            {
                return _equipment;
            }
        }

        public CharacterStats Stats
        {
            get
            {
                return Profile.Stats;
            }
        }

        public override void Destroy()
        {
            base.Destroy();
        }        
    }
}
